package com.friddle.util.Upload;

/**
 * Created by friddle on 15/3/25.
 */
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.List;
import java.util.Properties;

import org.apache.commons.lang3.tuple.MutablePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class SFTP {
	private static final Logger LOG = LoggerFactory.getLogger(SFTP.class);
	public static final int SFTP_DEFAULT_PORT = 22;

	public ChannelSftp getSFTPChannel(String FtpHost, String FtpPort, String FtpUserName, String FtpPasswd, int timeout)
			throws JSchException {
		Session session = this.getSession(FtpHost, FtpPort, FtpUserName, FtpPasswd, timeout);
		Channel channel = session.openChannel("sftp");
		channel.connect();
		return (ChannelSftp) channel;
	}

	public Session getSession(String FtpHost, String FtpPort, String FtpUserName, String FtpPasswd, int timeout) throws JSchException {
		Session session;
		int ftpPort = SFTP_DEFAULT_PORT;
		if (FtpPort != null && !FtpPort.equals("")) {
			ftpPort = Integer.valueOf(FtpPort);
		}
		JSch jsch = new JSch();
		session = jsch.getSession(FtpUserName, FtpHost, ftpPort);
		LOG.debug("Session created.");
		if (FtpPasswd != null) {
			session.setPassword(FtpPasswd);
		}
		Properties config = new Properties();
		config.put("StrictHostKeyChecking", "no");
		session.setConfig(config);
		session.setTimeout(timeout);
		session.connect();
		return session;
	}

	protected void transform(ChannelSftp ftp, String filename, String destName) throws Exception {
		OutputStream out = ftp.put(destName, ChannelSftp.OVERWRITE);
		byte[] buff = new byte[1024 * 256];
		int read;
		if (out != null) {
			InputStream is = new FileInputStream(filename);
			do {
				read = is.read(buff, 0, buff.length);
				if (read > 0) {
					out.write(buff, 0, read);
				}
				out.flush();
			} while (read >= 0);
		}
	}

	/***
	 * 
	 * @param host
	 * @param port
	 * @param username
	 * @param passwd
	 * @param file
	 * @param dest
	 * @return
	 */
	public MutablePair<Boolean, String> transformFiles(String host, String port, String username, String passwd, String file, String dest) {
		MutablePair<Boolean, String> answer = new MutablePair<>();
		try {
			ChannelSftp sftp = this.getSFTPChannel(host, port, username, passwd, 60000);
			this.transform(sftp, file, dest);
			this.closeChannel(sftp);
			answer.setLeft(true);
			answer.setRight("success");
		} catch (Exception e) {
			answer.setLeft(false);
			answer.setRight(e.getMessage());
		}
		return answer;
	}

	public MutablePair<Boolean, String> runCommands(String host, String port, String username, String passwd, List<String> commands)
			throws JSchException {
		MutablePair<Boolean, String> answer = new MutablePair<>();
		try {
			ChannelExec exec = this.getExecChannel(host, port, username, passwd);
			InputStream stream = exec.getInputStream();
			for (String command : commands) {
				exec.setCommand(command);
				exec.connect();
				BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
				String line;
				int index = 0;
				while ((line = reader.readLine()) != null) {
					System.out.println(++index + " : " + line);
				}
				exec.disconnect();
			}
			answer.setLeft(true);
			answer.setRight("success");
		} catch (Exception e) {
			answer.setLeft(false);
			answer.setRight(e.getMessage());
		}
		return answer;
	}

	public void executeShell(ChannelSftp channelSftp, String command) throws Exception {
		ChannelShell channel = (ChannelShell) channelSftp.getSession().openChannel("shell");
		channel.connect();
		InputStream instream = channel.getInputStream();
		OutputStream outstream = channel.getOutputStream();
		if (!command.endsWith("\n")) {
			command = command + " \n";
		}
		// 发送需要执行的SHELL命令，需要用\n结尾，表示回车
		outstream.write(command.getBytes());
		outstream.flush();
		// 获取命令执行的结果
		Thread.sleep(1000);
		if (instream.available() > 0) {
			byte[] data = new byte[instream.available()];
			int nLen = instream.read(data);
			if (nLen < 0) {
				throw new Exception("network error.");
			}
			// 转换输出结果并打印出来
			String temp = new String(data, 0, nLen, "utf-8");
			LOG.info(temp);
		}
		outstream.close();
		instream.close();
		if (command.contains("run.sh")) {
			while (true) {
				if (channel.isClosed()) {
					channel.connect();
					executeShell(channelSftp, command);
				}
				Thread.sleep(3000);
			}
		}
		channel.disconnect();
	}

	public ChannelExec getExecChannel(String host, String port, String username, String passwd) throws JSchException {
		Session session = this.getSession(host, port, username, passwd, 10000);
		Channel channel = session.openChannel("exec");
		return (ChannelExec) channel;
	}

	public void closeChannel(Channel channel) throws Exception {
		if (channel != null) {
			channel.disconnect();
		}
	}
}
